//
//  OYCategoriesController.m
//  ObjectiveYouTube
//
//  Created by Tristan O'Tierney on 3/15/08.
//  Copyright 2008 Tristan O'Tierney. All rights reserved.
//

#import <ObjectiveYouTube/ObjectiveYouTube.h>

static NSString *kOYCategoriesNoCategoriesFoundErrorDomain = @"OYCategoriesNoCategoriesFoundError";
const static int kOYCategoriesNoCategoriesFoundErrorCode = 400;

static NSString *kOYAssignableCategoryName = @"yt:assignable";
static NSString *kOYCategoryFileName = @"categories";
static NSString *kOYCategoryFileType = @"cat";

const static NSTimeInterval kOYCategoriesTimeoutInterval = 60.0f;

@interface OYCategoriesController (Private)
- (void)_delegateError:(NSString *)domain withCode:(int)code;
- (void)_delegateError:(NSError *)error;
- (void)_cleanupConnection;
- (void)_loadFromXMLDocument:(NSXMLDocument *)xmlDoc;
@end

@implementation OYCategoriesController
#pragma mark -
#pragma mark Initializers
#pragma mark -
- (id)initWithDelegate:(id)delegate {
	if ((self = [super init])) {
		[self setDelegate:delegate];
		
		_connection = nil;
		_data = nil;
		_categories = [[NSMutableArray alloc] init];
		
		// try and load the categories.cat in our framework bundle
		NSString *categoriesFile = [[NSBundle bundleForClass:[self class]] pathForResource:kOYCategoryFileName
																					ofType:kOYCategoryFileType];
		if (categoriesFile) {
			NSError *error = nil;
			NSURL *fileURL = [NSURL fileURLWithPath:categoriesFile];
			NSXMLDocument *doc = [[[NSXMLDocument alloc] initWithContentsOfURL:fileURL
																	   options:0
																		 error:&error] autorelease];
			if (!error) {
				[self _loadFromXMLDocument:doc];
			}
		}
	}
	
	return self;
}

- (void)dealloc {
	_delegate = nil;
	
	[self cancelRefresh];
	
	[_categories release];
	_categories = nil;
	
	[super dealloc];
}

#pragma mark -
#pragma mark Control methods
#pragma mark -

- (void)refreshCategories {
	if ([self isRefreshing]) {
		return;
	}
	
	NSURL *categoryURL = [NSURL URLWithString:kOYCategoryURL];
	NSURLRequest *request = [NSURLRequest requestWithURL:categoryURL
											 cachePolicy:NSURLRequestUseProtocolCachePolicy 
										 timeoutInterval:kOYCategoriesTimeoutInterval];
	
	_connection = [NSURLConnection connectionWithRequest:request delegate:self];
}

- (BOOL)isRefreshing {
	return _connection != nil;
}

- (void)cancelRefresh {
	if (_connection) {
		[_connection cancel];
		_connection = nil;
	}
	
	[_categories removeAllObjects];
	
	[self _cleanupConnection];
}

#pragma mark -
#pragma mark Accessors/Mutators
#pragma mark -

- (NSArray *)categories {
	return _categories;
}

- (id)delegate {
	return _delegate;
}

- (void)setDelegate:(id)delegate {
	_delegate = delegate;
}

#pragma mark -
#pragma mark Callbacks
#pragma mark -

// URL connection callbacks
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
	if (!_data) {
		_data = [[NSMutableData alloc] init];
	}
	
	[_data appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {	
	// parse the response
	NSError *error = nil;
	NSXMLDocument *xmlDoc = [[[NSXMLDocument alloc] initWithData:_data options:0 error:&error] autorelease];
	
	if (!error) {
		[self _loadFromXMLDocument:xmlDoc];
	}
	
	// clean up the connection
	[self _cleanupConnection];
	
	// let our delegate know we're finished
	if ([_categories count] && !error) {
		if (_delegate && [_delegate respondsToSelector:@selector(categories:refreshedWithCategories:)]) {
			[_delegate categories:self refreshedWithCategories:_categories];
		}
	} else if (error) {
		[self _delegateError:error];
	} else {
		[self _delegateError:kOYCategoriesNoCategoriesFoundErrorDomain
					withCode:kOYCategoriesNoCategoriesFoundErrorCode];
	}
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {	
	// clean up the connection
	[self _cleanupConnection];
	
	// let our delegate know we're finished
	[self _delegateError:kOYConnectionFailedErrorDomain
				withCode:kOYConnectionFailedErrorCode];
}
@end

@implementation OYCategoriesController (Private)
- (void)_delegateError:(NSString *)domain withCode:(int)code {
	NSError *error = [NSError errorWithDomain:domain
										 code:code
									 userInfo:nil];
	
	[self _delegateError:error];
}

- (void)_delegateError:(NSError *)error {
	if (_delegate && [_delegate respondsToSelector:@selector(categories:refreshFailedWithError:)]) {
		[_delegate categories:self refreshFailedWithError:error];
	}
}

- (void)_cleanupConnection {
	_connection = nil;
	[_data release];
	_data = nil;
}

- (void)_loadFromXMLDocument:(NSXMLDocument *)xmlDoc {
	[self willChangeValueForKey:@"categories"];
	[_categories removeAllObjects];
	
	NSArray *children = [[xmlDoc rootElement] children];
	NSEnumerator *en = [children objectEnumerator];
	NSXMLElement *child = nil;
	
	while ((child = [en nextObject]) != nil) {
		// Make sure the item is assignable
		NSArray *assignable = [child elementsForName:kOYAssignableCategoryName];
		
		if (assignable && [assignable count]) {
			OYCategory *category = [[[OYCategory alloc] initWithXMLElement:child] autorelease];
			if (category) {
				[_categories addObject:category];
			}
		}
	}
	
	[_categories sortUsingSelector:@selector(compareLabel:)];
	[self didChangeValueForKey:@"categories"];
}
@end